#include "gsmeg_link_map.h"

gsmeg_link_map_t *gsmeg_link_map_create(){
    z_hash_t *map = zH_init();
    if(map== NULL){
        Z_LOG_FATAL("init hash fail");
    }
    return map;
}

void gsmeg_link_map_destroy(gsmeg_link_map_t *map){
    if(map){
        z_pair_t *p = NULL;
        gsmeg_link_t *gsmeg_link = NULL;
        while(NULL != (p =zH_foreach(map,p))){
            gsmeg_link = (gsmeg_link_t *)(obj2ll(p->value_));
            gsmeg_link_destroy(gsmeg_link);
        }
        zH_free(map);
    }    
}

static int gsmeg_link_map_insert(gsmeg_link_map_t *map,long long channel,int state){
    _CHECK_NULL_RET_ERR_(map,-1)
    gsmeg_link_t *gsmeg_link = gsmeg_link_create(channel,state);
    if(gsmeg_link != NULL){
        return sge_hashmap_ptr_ll_insert(map,channel,(void *)gsmeg_link);
    }else{
        Z_LOG_FATAL("create gsmeg_link for channel[%l] fail",channel);
        return -1;
    }
}

static int gsmeg_link_map_delete(gsmeg_link_map_t *map,long long channel){
    _CHECK_NULL_RET_ERR_(map,-1)
    return sge_hashmap_ptr_ll_delete(map,channel); //will free mem when del
}

static int gsmeg_link_map_update_channel_state(gsmeg_link_map_t *map,long long channel,int state){
    _CHECK_NULL_RET_ERR_(map,-1)
    gsmeg_link_t *gsmeg_link  =(gsmeg_link_t *)sge_hashmap_ptr_ll_find(map,channel);
    if(gsmeg_link){
        return gsmeg_link_update_state(gsmeg_link,state);
    }else{
        Z_LOG_FATAL("channel[%l] not found in gsmeg link map",channel);
        return -1;
    }
}

int gsmeg_link_map_onconnected(gsmeg_link_map_t *map,long long channel){
    return gsmeg_link_map_insert(map,channel,GSMEG_LINK_CONNECTED);
}

int gsmeg_link_map_ondisconnected(gsmeg_link_map_t *map,long long channel){
    return gsmeg_link_map_delete(map,channel);
}

int gsmeg_link_map_onlogined(gsmeg_link_map_t *map,long long channel){
    return gsmeg_link_map_update_channel_state(map,channel,GSMEG_LINK_LOGINED);
}

void gsmeg_link_map_push_to_all_valid_link(gsmeg_link_map_t *map,char *gsmeg_msg,int con_len,int cmd){
    _CHECK_NULL_RET_(map)
    long long channel;
    z_pair_t *p = NULL;
    gsmeg_link_t *gsmeg_link = NULL;
    while( NULL != (p = zH_foreach(map,p))){
        channel = ((z_ll_t*)p->key_)->l_;
        gsmeg_link = (gsmeg_link_t *)(obj2ll(p->value_));
        if(TRUE == gsmeg_link_is_valid(gsmeg_link)){
            if( 0 == gsmeg_link_send_msg(gsmeg_link,gsmeg_msg,con_len,cmd)){
                continue;
            }else{
                Z_LOG_DEBUG("gsmeg channel[%l] push fail",channel);
            }
        }else{
            Z_LOG_DEBUG("gsmeg channel[%l] is invalid",channel);
        }    
    }
    return;
}

void gsmeg_link_map_push_to_one_valid_link(gsmeg_link_map_t *map,char *gsmeg_msg,int con_len,int cmd){
    _CHECK_NULL_RET_(map)
    long long channel =0;;
    z_pair_t *p = NULL;
    gsmeg_link_t *gsmeg_link = NULL;
    while( NULL != (p = zH_foreach(map,p))){
        channel = ((z_ll_t*)p->key_)->l_;
        gsmeg_link = (gsmeg_link_t *)(obj2ll(p->value_));
        if(TRUE == gsmeg_link_is_valid(gsmeg_link)){
            if( 0 == gsmeg_link_send_msg(gsmeg_link,gsmeg_msg,con_len,cmd)){
                break;
            }else{
                Z_LOG_DEBUG("gsmeg channel[%l] push fail",channel);
            }
        }else{
            Z_LOG_DEBUG("gsmeg channel[%l] is invalid",channel);
        }    
    }
    return;
}

void gsmeg_link_map_push_by_channel(gsmeg_link_map_t *map,long long channel,char *gsmeg_msg,int con_len,int cmd){
    _CHECK_NULL_RET_(map)
    gsmeg_link_t *gsmeg_link  =(gsmeg_link_t *)sge_hashmap_ptr_ll_find(map,channel);
    if(gsmeg_link){
        if(0!= gsmeg_link_send_msg(gsmeg_link,gsmeg_msg,con_len,cmd)){
            Z_LOG_FATAL("gsmeg channel[%l] push fail",channel);
        }
    }else{
        Z_LOG_FATAL("channel[%l] not found in gsmeg link map",channel);
    }
    return;
}

int gsmeg_link_map_is_valid_channel(gsmeg_link_map_t *map,long long channel){
    _CHECK_NULL_RET_ERR_(map,FALSE)
    gsmeg_link_t *gsmeg_link  =(gsmeg_link_t *)sge_hashmap_ptr_ll_find(map,channel);
    if(gsmeg_link){
        return gsmeg_link_is_valid(gsmeg_link);
    }else{
        return FALSE;
    }
}
